package AircraftDesignKg.server;

import AircraftDesignKg.constant.ServiceConstant;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.apache.pdfbox.rendering.PDFRenderer;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.UUID;
/**
 * 文件服务
 */
@Service
public class FileService {
    // TODO 谢未
    /*
     * 该服务的功能大致流程参考如下:
     *  1. 文件合法性校验;
     *  2. 在服务器内保存文件(涉及到生成唯一文件名, 可考虑使用UUID或时间戳作为前缀);
     *  3. 将文件解析为字符串(至少需要支持.doc .docx .txt, 最好支持 .pdf)。
     */
    // 可前往 ServiceImpl 查看用法

    //记录日志
    private static final Logger log = LogManager.getLogger(FileService.class);
    // 文件保存根目录
    private static final String SAVE_PATH = ServiceConstant.FILE_SAVE_PATH.getValue();

    //支持的文件类型
    private static final String[] ALLOWED_EXTENSIONS = {
            "text/plain",
            "application/msword",
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/pdf"
    };
    /**
     * 服务对外唯一接口方法
     * @param file 文件
     * @return 文件解析后的字符串
     */
    public String handleFile(MultipartFile file) throws Exception {
        // 异常向上抛, 不要在本级吞掉, 但需要打日志
        try{
            //校验文件合法性
            validateFile(file);
            //保存文件并获取保存路径
            Path savedFilePath = saveFile(file);
            log.info("文件保存成功: {}", savedFilePath);
            //解析文件为字符串
            return parseFileContent(savedFilePath, file.getContentType());
        }catch (Exception e){
            log.error("[error] 文件处理失败: {}", e.getMessage());
            throw e;
        }
    }




    private void validateFile(MultipartFile file) {
        //检验文件是否为空
        if(file.isEmpty()){
            throw new IllegalArgumentException("上传文件为空");
        }
        //检验文件类型
        String contentType = file.getContentType();
        boolean isAllowed = false;
        for (String allowed : ALLOWED_EXTENSIONS) {
            if (allowed.equalsIgnoreCase(contentType)) {
                isAllowed = true;
                break;
            }
        }
        if(!isAllowed){
            throw new IllegalArgumentException("不支持的文件类型: " + contentType);
        }
    }
    private Path saveFile(MultipartFile file) throws IOException {
        //没有目录就创建目录
        Path saveDir = Paths.get(SAVE_PATH);
        if (!Files.exists(saveDir)) {
            Files.createDirectories(saveDir);
        }
        //生成唯一文件名
        String originalFilename = file.getOriginalFilename();
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String newFilename = UUID.randomUUID() + extension;
        //保存文件
        Path targetPath = saveDir.resolve(newFilename);
        Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
        return targetPath;
    }
    private String parseFileContent(Path savedFilePath, String contentType) throws IOException {
        switch (contentType) {
            case "text/plain":
                return parseTxt(savedFilePath);
            case "application/msword":
            case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
                return parseWord(savedFilePath);
            case "application/pdf":
                return parsePdf(savedFilePath);
            default:
                throw new UnsupportedOperationException("未支持的文件解析类型: " + contentType);
        }
    }

    private String parsePdf(Path savedFilePath) throws IOException{
        try (PDDocument document = Loader.loadPDF(savedFilePath.toFile())) {
            PDFTextStripper stripper = new PDFTextStripper();
            return stripper.getText(document);
        }
    }

    private String parseWord(Path savedFilePath) throws IOException {
        try (InputStream is = Files.newInputStream(savedFilePath);
             XWPFDocument document = new XWPFDocument(is);
             XWPFWordExtractor extractor = new XWPFWordExtractor(document)) {
            return extractor.getText();
        }
    }

    private String parseTxt(Path savedFilePath) throws IOException {
        return new String(Files.readAllBytes(savedFilePath));
    }
}
